package com.xxl.job.admin.core.thread;

import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobLogReport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * job log report helper
 *
 * @author xuxueli 2019-11-22
 */
public class JobLogReportHelper {

	private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class);

	private static JobLogReportHelper instance = new JobLogReportHelper();

	public static JobLogReportHelper getInstance() {
		return instance;
	}

	private Thread logrThread;

	private volatile boolean toStop = false;

	public void start() {
		logrThread = new Thread(new Runnable() {

			@Override
			public void run() {

				// last clean log time
				long lastCleanLogTime = 0;

				while (!toStop) {

					// 1、log-report refresh: refresh log report in 3 days
					try {

						for (int i = 0; i < 3; i++) {

							// today
							Calendar itemDay = Calendar.getInstance();
							itemDay.add(Calendar.DAY_OF_MONTH, -i);
							itemDay.set(Calendar.HOUR_OF_DAY, 0);
							itemDay.set(Calendar.MINUTE, 0);
							itemDay.set(Calendar.SECOND, 0);
							itemDay.set(Calendar.MILLISECOND, 0);

							Date todayFrom = itemDay.getTime();

							itemDay.set(Calendar.HOUR_OF_DAY, 23);
							itemDay.set(Calendar.MINUTE, 59);
							itemDay.set(Calendar.SECOND, 59);
							itemDay.set(Calendar.MILLISECOND, 999);

							Date todayTo = itemDay.getTime();

							// refresh log-report every minute
							XxlJobLogReport xxlJobLogReport = new XxlJobLogReport();
							xxlJobLogReport.setTriggerDay(todayFrom);
							xxlJobLogReport.setRunningCount(0);
							xxlJobLogReport.setSucCount(0);
							xxlJobLogReport.setFailCount(0);

							Map<String, Object> triggerCountMap = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao()
									.findLogReport(todayFrom, todayTo);
							if (triggerCountMap != null && triggerCountMap.size() > 0) {
								int triggerDayCount = triggerCountMap.containsKey("triggerDayCount")
										? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCount"))) : 0;
								int triggerDayCountRunning = triggerCountMap.containsKey("triggerDayCountRunning")
										? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountRunning")))
										: 0;
								int triggerDayCountSuc = triggerCountMap.containsKey("triggerDayCountSuc")
										? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountSuc")))
										: 0;
								int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;

								xxlJobLogReport.setRunningCount(triggerDayCountRunning);
								xxlJobLogReport.setSucCount(triggerDayCountSuc);
								xxlJobLogReport.setFailCount(triggerDayCountFail);
							}

							// do refresh
							int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao()
									.update(xxlJobLogReport);
							if (ret < 1) {
								XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().save(xxlJobLogReport);
							}
						}

					}
					catch (Exception e) {
						if (!toStop) {
							logger.error(">>>>>>>>>>> xxl-job, job log report thread error:{}", e);
						}
					}

					// 2、log-clean: switch open & once each day
					if (XxlJobAdminConfig.getAdminConfig().getLogretentiondays() > 0
							&& System.currentTimeMillis() - lastCleanLogTime > 24 * 60 * 60 * 1000) {

						// expire-time
						Calendar expiredDay = Calendar.getInstance();
						expiredDay.add(Calendar.DAY_OF_MONTH,
								-1 * XxlJobAdminConfig.getAdminConfig().getLogretentiondays());
						expiredDay.set(Calendar.HOUR_OF_DAY, 0);
						expiredDay.set(Calendar.MINUTE, 0);
						expiredDay.set(Calendar.SECOND, 0);
						expiredDay.set(Calendar.MILLISECOND, 0);
						Date clearBeforeTime = expiredDay.getTime();

						// clean expired log
						List<Long> logIds = null;
						do {
							logIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findClearLogIds(0, 0,
									clearBeforeTime, 0, 1000);
							if (logIds != null && logIds.size() > 0) {
								XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().clearLog(logIds);
							}
						}
						while (logIds != null && logIds.size() > 0);

						// update clean time
						lastCleanLogTime = System.currentTimeMillis();
					}

					try {
						TimeUnit.MINUTES.sleep(1);
					}
					catch (Exception e) {
						if (!toStop) {
							logger.error(e.getMessage(), e);
						}
					}

				}

				logger.info(">>>>>>>>>>> xxl-job, job log report thread stop");

			}
		});
		logrThread.setDaemon(true);
		logrThread.setName("xxl-job, admin JobLogReportHelper");
		logrThread.start();
	}

	public void toStop() {
		toStop = true;
		// interrupt and wait
		logrThread.interrupt();
		try {
			logrThread.join();
		}
		catch (InterruptedException e) {
			logger.error(e.getMessage(), e);
		}
	}

}
